package com.rui.study.test.nio;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

/**
 * @program: study
 * @description:
 * @author: Yaowr
 * @create: 2019-03-25 11:21
 **/
public class Server {

    public static final Logger LOGGER = LoggerFactory.getLogger(Server.class);

    private static void doServer() {
        Selector serverSelector;
        Selector clientSelector;
        try {
            serverSelector = Selector.open();
            clientSelector = Selector.open();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        new Thread(()-> {
            try {
                ServerSocketChannel serverChannel = ServerSocketChannel.open();
                serverChannel.socket().bind(new InetSocketAddress(5678));
                serverChannel.configureBlocking(false);
                serverChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
                while (true) {
                    int ss;
                    if ((ss = serverSelector.select()) > 0) {
                        LOGGER.info("server select: {}", ss);
                        Set<SelectionKey> selectionKeys = serverSelector.selectedKeys();
                        Iterator<SelectionKey> it = selectionKeys.iterator();
                        while (it.hasNext()) {
                            SelectionKey key = it.next();
                            if (key.isAcceptable()) {
                                try {
                                    SocketChannel clientChannel = ((ServerSocketChannel)key.channel()).accept();
                                    clientChannel.configureBlocking(false);
                                    clientChannel.register(clientSelector, SelectionKey.OP_READ);
                                } finally {
                                    it.remove();
                                }
                            }
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }, "boss").start();

        new Thread(()-> {
            try {
                while (true) {
                    int cs;
                    if ((cs = clientSelector.select()) > 0) {
                        LOGGER.info("client select: {}", cs);
                        Set<SelectionKey> selectionKeys = clientSelector.selectedKeys();
                        Iterator<SelectionKey> it = selectionKeys.iterator();
                        while (it.hasNext()) {
                            SelectionKey key = it.next();
                            if (key.isReadable()) {
                                try {
                                    SocketChannel clientSocket = (SocketChannel) key.channel();
                                    ByteBuffer buff = ByteBuffer.allocate(1024);
                                    clientSocket.read(buff);
                                    buff.flip();
                                    LOGGER.info("Received: [{}]", Charset.defaultCharset().newDecoder().decode(buff).toString());
                                } finally {
                                    it.remove();
                                    key.interestOps(SelectionKey.OP_READ);
                                }
                            }
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }, "worker").start();
        LOGGER.info("server start");
    }

    public static void main(String[] args) {
        doServer();
    }
}
